home *** CD-ROM | disk | FTP | other *** search
/ United Public Domain Gold 2 / United Public Domain Gold 2.iso / utilities / pu660.dms / pu660.adf / Vmem / vmem.c < prev    next >
C/C++ Source or Header  |  1991-12-19  |  22KB  |  879 lines

  1. /*
  2. ** VMEM - a virtual memory manager for the Amiga operating system
  3. **
  4. ** Version 0.1 ©1990 by Edward Hutchins
  5. ** Based in part on the SetCPU program by Dave Haynie
  6. ** Authors:
  7. **
  8. **    Edward Hutchins: eah1@cec1.wustl.edu
  9. **    Loren Rittle: l-rittle@uiuc.edu
  10. **
  11. ** Revisions:
  12. ** 10/29/91 cleaned up code somewhat - Ed.
  13. ** 12/19/91 made the spy faster with SpyPenCache - Ed.
  14. ** 12/19/91 code released as freeware under the GNU general public license - Ed.
  15. **
  16. **    This program is free software; you can redistribute it and/or modify
  17. **    it under the terms of the GNU General Public License as published by
  18. **    the Free Software Foundation; either version 1, or (at your option)
  19. **    any later version.
  20. **
  21. **    This program is distributed in the hope that it will be useful,
  22. **    but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. **    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24. **    GNU General Public License for more details.
  25. **
  26. **    You should have received a copy of the GNU General Public License
  27. **    along with this program; if not, write to the Free Software
  28. **    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. **
  30. */
  31.  
  32. #include "vmem.h"
  33.  
  34. /*
  35. ** typedefs and defines
  36. */
  37.  
  38. #define VMEM_VERSION        "0.4"                        /* vmem version */
  39. #define VMEM_NAME            "virtual memory"            /* memory pool name */
  40. #define VMEM_BASE            0x01000000                    /* virt mem base addr */
  41. #define VMEM_PRI            20                            /* allocation priority */
  42. #define DEF_SWAP_FILE_NAME    "work:.VMEM_PAGES"            /* should be SYS: */
  43. #define DEF_NUMFRAMES        0x80                        /* 1M of frames */
  44. #define DEF_NUMPAGES        0x200                        /* 4M of virt mem */
  45. #define INITIAL_SHIFT        5                            /* 5 + 14 + 13 == 32 */
  46. #define PAGE_SIZE            0x2000                        /* 8k pages */
  47. #define PAGE_SIZE_MASK        0x1FFF                        /* mask off 8k */
  48. #define PAGE_SIZE_INDEX        13                            /* 8k page offset bits */
  49. #define PAGE_TABLE_INDEX    14                            /* TIA index bits */
  50. #define PAGE_TABLE_MIN        0x800                        /* 16M of 8k pages */
  51. #define PAGEDAEMON_PRI        50                            /* VERY high priority */
  52. #define AGEING_PERIOD        100000                        /* 0.1 second */
  53. #define FASTPUB (MEMF_FAST | MEMF_PUBLIC)                /* fast public memory */
  54.  
  55. /* spy stuff */
  56. #define WIDTH 320
  57. #define HEIGHT 32
  58. #define DEPTH 3
  59. #define MAX_PEN 8
  60.  
  61. /*
  62. ** globals
  63. */
  64.  
  65. struct ExecBase        *ExecBase;
  66. struct GfxBase        *GfxBase;
  67. struct IntuitionBase *IntuitionBase;
  68. struct Window        *window;
  69. struct RastPort        *RP;
  70.  
  71. UWORD                NumFrames = DEF_NUMFRAMES;        /* number of frames */
  72. UWORD                NumPages = DEF_NUMPAGES;        /* number of pages */
  73. CPTR                ROMBase;                        /* ROMs mapped to this RAM */
  74. CPTR                FrameBase;                        /* frame table */
  75. PFRAME_DESC            FrameTable;                        /* frame descriptors */
  76. PPD_SHORT            PageTable;                        /* page table */
  77. CPTR                SysBusErrHandler;                /* default bus fault vector */
  78. ULONG                SwapFile;                        /* handle to swap file */
  79. ULONG                PageDaemonSig;                    /* daemon's signal */
  80. struct Task         *PageDaemonTask;                /* the pager (us for now) */
  81. struct MemHeader    *FastMemHeader;                    /* public memory area */
  82. struct MinList        PageFaultList;                    /* queue faults here */
  83. char                SwapFileName[80];                /* swap file name */
  84. WORD                PendingPageFaults;                /* page faults to be served */
  85.  
  86. /* this will break once NumPages gets parsed from the command line... */
  87. BYTE                SpyPenCache[PAGE_TABLE_MIN + DEF_NUMPAGES];
  88.  
  89. #define VMEM_LENGTH    (NumPages * PAGE_SIZE)            /* virt mem size */
  90. #define VMEM_END    (VMEM_BASE + VMEM_LENGTH)        /* end of virt mem */
  91.  
  92. /* get a frame index from a page address */
  93. #define PAGE_TO_FRAME(pd) ((((pd)&PD_ADDR_MASK)-(ULONG)FrameBase)/PAGE_SIZE)
  94.  
  95. /*
  96. ** locals
  97. */
  98.  
  99. UWORD ctable[] =
  100. {0x0000, 0x0222, 0x0630, 0x0f00, 0x000f, 0x0070, 0x0304, 0x0740 };
  101.  
  102. /* spy pen types (map to colors above) */
  103. enum { PEN_UNUSED, PEN_VIRT, PEN_INVALID, PEN_MOD,
  104.        PEN_USED, PEN_WP, PEN_CI, PEN_FRAME };
  105.  
  106. /*
  107. ** We don't need any termination routines
  108. */
  109.  
  110. VOID MemCleanup(VOID) {}
  111.  
  112. /*
  113. ** AllocBlocks - allocate memory aligned by lBound+1
  114. */
  115.  
  116. static void *AllocBlocks( ULONG lSize, ULONG lBound )
  117. {
  118.    void *mem, *aligned;
  119.  
  120.    if (!(mem = AllocMem( lSize + lBound, FASTPUB ))) return( NULL );
  121.    Forbid();
  122.    aligned = (void *)(((ULONG)mem + lBound) & ~(lBound));
  123.    FreeMem( mem, lSize + lBound );
  124.    mem = AllocAbs( lSize, aligned );
  125.    Permit();
  126.    return( mem );
  127. }
  128.  
  129. /*
  130. ** AllocVMem - find the fast memory list, allocate needed physical space
  131. */
  132.  
  133. BOOL AllocVMem(VOID)
  134. {
  135.     ULONG FrameSize = NumFrames * PAGE_SIZE;
  136.     ULONG FrameTableSize = NumFrames * sizeof(FRAME_DESC);
  137.     ULONG PageTableSize = (PAGE_TABLE_MIN + NumPages) * sizeof(PD_SHORT);
  138.     BOOL bSuccess = FALSE;
  139.  
  140.     /* prevent mucking about with the MemLists */
  141.     Disable();
  142.  
  143.     /* find a fast+public memory MemHeader for the fault nodes */
  144.     /* note: this works because lh_Head and ln_Succ are the same */
  145.     FastMemHeader = (struct MemHeader *)&(ExecBase->MemList);
  146.     if (FastMemHeader == NULL)
  147.     {
  148.         Enable();
  149.         goto BailOut;
  150.     }
  151.  
  152.     for (;;)
  153.     {
  154.         FastMemHeader = (struct MemHeader *) FastMemHeader->mh_Node.ln_Succ;
  155.         if (FastMemHeader == NULL) goto BailOut;
  156.         if ((FastMemHeader->mh_Attributes & FASTPUB) == FASTPUB) break;
  157.     }
  158.  
  159.     Enable();
  160.  
  161.     /* allocate in this order to minimize fragging */
  162.     if (!(FrameBase = (CPTR)AllocBlocks( FrameSize, PAGE_SIZE_MASK )))
  163.         goto BailOut;
  164.  
  165.     if (!(ROMBase = (CPTR)AllocBlocks( ROMSIZE, PAGE_SIZE_MASK )))
  166.         goto BailOut;
  167.  
  168.     /* the !@#%!&* CRP needs to be aligned to 16-byte boundaries */
  169.     if (!(PageTable = (PPD_SHORT)AllocBlocks( PageTableSize, 15 )))
  170.         goto BailOut;
  171.  
  172.     if (!(FrameTable = (PFRAME_DESC)AllocBlocks( FrameTableSize, 15 )))
  173.         goto BailOut;
  174.  
  175.     bSuccess = TRUE;
  176.  
  177.     /* come here to bomb */
  178. BailOut:
  179.     return (bSuccess);
  180. }
  181.  
  182. /*
  183. ** SetPageTableFlags - set flags in the page table over a range of addresses
  184. */
  185.  
  186. VOID SetPageTableFlags(ULONG begad, ULONG endad, ULONG Flags)
  187. {
  188.     while (begad < endad)
  189.     {
  190.         PageTable[begad / PAGE_SIZE] |= Flags;
  191.         begad += PAGE_SIZE;
  192.     }
  193. }
  194.  
  195. /*
  196. ** ClearPageTableFlags - clear flags in the page table over a range of addresses
  197. */
  198.  
  199. VOID ClearPageTableFlags(ULONG begad, ULONG endad, ULONG Flags)
  200. {
  201.     while (begad < endad)
  202.     {
  203.         PageTable[begad / PAGE_SIZE] &= ~Flags;
  204.         begad += PAGE_SIZE;
  205.     }
  206. }
  207.  
  208. /*
  209. ** This routine creates the Fast ROM and sets up memory.
  210. **
  211. ** Address:
  212. ** 31        23        15        7        0
  213. ** +------+--------------+----------+
  214. ** | IS 5 |    TIA 14    |  PS  13  | 13 bits = 8K pages
  215. ** +------+--------------+----------+
  216. **
  217. ** First 5 bits of logical address -> shifted into the bit bucket
  218. ** next 14 bits of logical address -> index into PageTable (level A)
  219. ** last 13 bits of logical address -> offset into page
  220. */
  221.  
  222. BOOL CreatePageTable(VOID)
  223. {
  224.     ULONG i, myCRP[2], myTC;
  225.  
  226. #if defined(DEBUG)
  227.     printf("AllocVMem()\n");
  228. #endif
  229.  
  230.     /* allocate all needed memory */
  231.     if (!AllocVMem()) return (FALSE);
  232.  
  233. #if defined(DEBUG)
  234.     printf("CopyMemQuick()\n");
  235. #endif
  236.  
  237.     /* Here I set up the ROM, as quickly as possible! */
  238.     CopyMemQuick((ULONG *)ROMBASE, (ULONG *)ROMBase, ROMSIZE);
  239.  
  240. #if defined(DEBUG)
  241.     printf("Translation setup...\n");
  242. #endif
  243.  
  244.     /* transparent translation of existing address space... */
  245.     for (i = 0x00000000; i < ROMBASE; i += PAGE_SIZE)
  246.     {
  247.         PageTable[i / PAGE_SIZE] = PD_ADDR(i) | PD_DT_PAGE;
  248.     }
  249.  
  250.     /* ...except re-map the ROM image and write protect it... */
  251.     for (i = ROMBASE; i < 0x00FFFFFF; i += PAGE_SIZE)
  252.     {
  253.         PageTable[i / PAGE_SIZE] = PD_ADDR(ROMBase + (i - ROMBASE)) | PD_WP | PD_DT_PAGE;
  254.     }
  255.  
  256.     /* ...as well as the physical memory containing the ROM image */
  257.     SetPageTableFlags( (ULONG)ROMBase, (ULONG)ROMBase + ROMSIZE, PD_WP );
  258.  
  259.     /*
  260.     ** cache-inhibit chip memory and custom registers
  261.     **
  262.     ** $00000000
  263.     **        |            2M chip memory, cache inhibit
  264.     ** $001FFFFF
  265.     ** $00200000
  266.     **        |            8M fast ram, public
  267.     ** $00BFFFFF
  268.     ** $00A00000
  269.     **        |            2M reserved area, cache inhibit anyway
  270.     ** $00BFFFFF
  271.     ** $00C00000
  272.     **        |            1M fast (slow really) ram on some machines, public
  273.     ** $00CFFFFF
  274.     ** $00D00000
  275.     **        |            2M custom chip area, cache inhibit
  276.     ** $00F7FFFF
  277.     ** $00F80000
  278.     **        |            256K system rom area (part mapped to FASTROM)
  279.     ** $00FFFFFF
  280.     ** $01000000
  281.     **        |            (up to) 16M virtual memory area
  282.     ** $01FFFFFF
  283.     */
  284.  
  285.     /* set up cache-inhibit */
  286.     SetPageTableFlags(0x00000000, 0x001FFFFF, PD_CI);
  287.     SetPageTableFlags(0x00A00000, 0x00BFFFFF, PD_CI);
  288.     SetPageTableFlags(0x00D00000, 0x00F7FFFF, PD_CI);
  289.  
  290.     /* map the first of the virtual pages to the available frames */
  291.     for (i = 0; i < NumFrames; ++i)
  292.     {
  293.         FrameTable[i].Age = 0;
  294.         FrameTable[i].PageIndex = PAGE_TABLE_MIN + i;
  295.         PageTable[PAGE_TABLE_MIN + i] = PD_ADDR(FrameBase + (i * PAGE_SIZE)) | PD_DT_PAGE;
  296.     }
  297.  
  298.     /* clear out the rest of virtual memory to invalid status */
  299.     for (i = NumFrames; i < NumPages; ++i)
  300.     {
  301.         PageTable[PAGE_TABLE_MIN + i] = PD_DT_INVALID;
  302.     }
  303.  
  304.     /*
  305.     ** Now I have to set up the MMU.  The CPU Root Pointer tells the MMU about
  306.     ** the table I've set up, and the Translation Control register will turn
  307.     ** the thing on.  Note that the first half of the CRP is control data, the
  308.     ** second the address of my table.
  309.     */
  310.  
  311. #if defined(DEBUG)
  312.     printf("CRP and TC Setup...\n");
  313. #endif
  314.  
  315.     Disable();
  316.     SetTC(0);
  317.     myCRP[0] = CRP_LIMIT(PAGE_TABLE_MIN + NumPages - 1) | CRP_SG | CRP_DT_V4BYTE;
  318.     myCRP[1] = (ULONG) PageTable;
  319.     SetCRP(myCRP);
  320.     myTC = TC_ENB | TC_IS(INITIAL_SHIFT) | TC_TIA(PAGE_TABLE_INDEX) |
  321.         TC_TIB(0) | TC_TIC(0) | TC_TID(0) | TC_PS(PAGE_SIZE_INDEX);
  322.     SetTC(myTC);
  323.     Enable();
  324.  
  325.     return (TRUE);
  326. }
  327.  
  328. /*
  329. ** AddVirtMem - add the virtual memory to the system free list
  330. */
  331.  
  332. VOID AddVirtMem(VOID)
  333. {
  334.     static char VirtMemName[] = VMEM_NAME;
  335.  
  336.     /* the page table better have a valid descriptor for the first page... */
  337.     AddMemList(VMEM_LENGTH, MEMF_FAST, VMEM_PRI, VMEM_BASE, VirtMemName);
  338. }
  339.  
  340. /*
  341. ** ShowFrameTableAges - show the page age table
  342. */
  343.  
  344. VOID ShowFrameTableAges(VOID)
  345. {
  346.     PFRAME_DESC pFrame = &FrameTable[0];
  347.     PFRAME_DESC pFrameEnd = &FrameTable[NumFrames];
  348.     PFRAME_DESC pOldest = pFrame;
  349.     UWORD FrameIndex = 0;
  350.  
  351.     while (pFrame < pFrameEnd)
  352.     {
  353.         printf("%d(%4.4x,%4.4x) ", FrameIndex, pFrame->Age, pFrame->PageIndex);
  354.         if (FrameIndex % 4 == 0) printf("\n");
  355.         ++FrameIndex, ++pFrame;
  356.     }
  357.     printf("\n\n");
  358. }
  359.  
  360. /*
  361. ** AgeFrameTable - age the frame table
  362. */
  363.  
  364. VOID AgeFrameTable(VOID)
  365. {
  366.     PFRAME_DESC pFrame = &FrameTable[0];
  367.     PFRAME_DESC pFrameEnd = &FrameTable[NumFrames];
  368.  
  369.     Disable();
  370.     while (pFrame < pFrameEnd)
  371.     {
  372.         PPD_SHORT pTbl = &PageTable[pFrame->PageIndex];
  373.         if (*pTbl & PD_USED)
  374.         {
  375.             *pTbl &= ~PD_USED;
  376.             pFrame->Age /= 2;
  377.         }
  378.         else if (pFrame->Age < AGE_MAX) ++(pFrame->Age);
  379.         ++pFrame;
  380.     }
  381.     Enable();
  382. }
  383.  
  384. /*
  385. ** CreateSwapFile - open and allocate the swap file
  386. **
  387. ** Call AFTER AllocVMem is done
  388. */
  389.  
  390. BOOL CreateSwapFile(VOID)
  391. {
  392.     ULONG Offset, SizeNeeded = NumPages * PAGE_SIZE;
  393.     ULONG BuffSize = NumFrames * PAGE_SIZE;
  394.     BOOL bSuccess = FALSE;
  395.  
  396. #if defined(DEBUG)
  397.     printf("opening file, ");
  398. #endif
  399.  
  400.     /* get an exclusive lock on this file */
  401.     SwapFile = Open(SwapFileName, MODE_OLDFILE);
  402.     if (SwapFile == 0)
  403.     {
  404.         SwapFile = Open(SwapFileName, MODE_NEWFILE);
  405.         if (SwapFile == 0) return (FALSE);
  406.     }
  407.  
  408.     /* make sure the file is at least big enough */
  409.     if (Seek(SwapFile, 0, OFFSET_END) == -1) goto Abort;
  410.     if ((Offset = Seek(SwapFile, 0, OFFSET_CURRENT)) == -1) goto Abort;
  411.  
  412.     /* is it already big enough? */
  413.     if (Offset >= SizeNeeded)
  414.     {
  415.         bSuccess = TRUE;
  416.         goto Abort;
  417.     }
  418.  
  419. #if defined(DEBUG)
  420.     printf("clearing buffer, ");
  421. #endif
  422.  
  423.     /* clear out the buffer */
  424.     {
  425.         char *p = FrameBase;
  426.         char *e = FrameBase + BuffSize;
  427.         while (p < e) *p++ = '\0';
  428.     }
  429.  
  430.     SizeNeeded -= Offset;
  431.  
  432. #if defined(DEBUG)
  433.     printf("writing (%ld) ", SizeNeeded);
  434. #endif
  435.  
  436.     while (SizeNeeded > BuffSize)
  437.     {
  438.         if (Write(SwapFile, FrameBase, BuffSize) != BuffSize) goto Abort;
  439.         SizeNeeded -= BuffSize;
  440.  
  441. #if defined(DEBUG)
  442.         printf(". ");
  443. #endif
  444.     }
  445.  
  446.     if (Write(SwapFile, FrameBase, SizeNeeded) == SizeNeeded) bSuccess = TRUE;
  447.  
  448. Abort:
  449.  
  450. #if defined(DEBUG)
  451.     printf("closing\n");
  452. #endif
  453.  
  454.     Close(SwapFile);
  455.     return (bSuccess);
  456. }
  457.  
  458. /*
  459. ** StealPage - choose the oldest page and discard it, return it's index
  460. */
  461.  
  462. UWORD StealPage(VOID)
  463. {
  464.     PFRAME_DESC pFrame = &FrameTable[0];
  465.     PFRAME_DESC pFrameEnd = &FrameTable[NumFrames];
  466.     PFRAME_DESC pOldest = pFrame;
  467.     UWORD Wage = WAGE(pOldest);
  468.     UWORD FrameIndex;
  469.     PD_SHORT pd;
  470.  
  471.     Disable();
  472.  
  473.     /* find the oldest page */
  474.     while (++pFrame < pFrameEnd) if (WAGE(pFrame) > Wage)
  475.     {
  476.         pOldest = pFrame;
  477.         Wage = WAGE(pOldest);
  478.     }
  479.  
  480.     FrameIndex = (((ULONG) pOldest - (ULONG) FrameTable) / sizeof(FRAME_DESC));
  481.  
  482.     /* mark the stolen page as invalid */
  483.     pd = PageTable[pOldest->PageIndex];
  484.     PageTable[pOldest->PageIndex] = PD_DT_INVALID;
  485.  
  486.     Enable();
  487.  
  488.     /* if the stolen page has been modified, we need to save it */
  489.     if (pd & PD_MOD)
  490.     {
  491.         ULONG FrameOffset = FrameIndex * PAGE_SIZE;
  492.         ULONG PageOffset = (pOldest->PageIndex * PAGE_SIZE) - VMEM_BASE;
  493.  
  494.         if ((SwapFile = Open(SwapFileName, MODE_OLDFILE)) == 0)
  495.         {
  496. #if defined(DEBUG)
  497.             printf("StealPage open file failed! (%s)\n", SwapFileName);
  498. #endif
  499.             Alert(-1L, 1);
  500.         }
  501.         Seek(SwapFile, PageOffset, OFFSET_BEGINNING);
  502.         Write(SwapFile, FrameBase + FrameOffset, PAGE_SIZE);
  503.         Close(SwapFile);
  504.  
  505. #if defined(DEBUG_PAGING)
  506.         printf("page %d (%lx) swapped out, ", pOldest->PageIndex, PageOffset);
  507. #endif
  508.     }
  509.  
  510.     return (FrameIndex);
  511. }
  512.  
  513. /*
  514. ** LockPage - check if a page is swapped in, and lock it if so
  515. */
  516.  
  517. BOOL LockPage(CPTR Address)
  518. {
  519.     PD_SHORT pd;
  520.  
  521.     if (Address < VMEM_BASE) return (TRUE);
  522.  
  523.     pd = PageTable[Address / PAGE_SIZE];
  524.  
  525.     /* the page is swapped out, so swap it in later */
  526.     if ((pd & PD_DT_MASK) == PD_DT_INVALID) return (FALSE);
  527.  
  528.     /* hopefully we won't get paged out right away */
  529.     FrameTable[PAGE_TO_FRAME(pd)].Age = 0;
  530.     return (TRUE);
  531. }
  532.  
  533. /*
  534. ** LoadPage - load a swapped out page, stealing unlocked pages only
  535. */
  536.  
  537. VOID LoadPage(CPTR Address)
  538. {
  539.     UWORD PageIndex = Address / PAGE_SIZE;
  540.     ULONG PageOffset = (PageIndex * PAGE_SIZE) - VMEM_BASE;
  541.     UWORD FrameIndex;
  542.     ULONG FrameOffset;
  543.  
  544.     /* has this page already been fixed? */
  545.     if ((PageTable[PageIndex] & PD_DT_MASK) == PD_DT_PAGE) return;
  546.  
  547.     FrameOffset = (FrameIndex = StealPage()) * PAGE_SIZE;
  548.  
  549.     if ((SwapFile = Open(SwapFileName, MODE_OLDFILE)) == 0)
  550.     {
  551. #if defined(DEBUG)
  552.         printf("LoadPage open file failed! (%s)\n", SwapFileName);
  553. #endif
  554.         Alert(-1L, 2);
  555.     }
  556.     Seek(SwapFile, PageOffset, OFFSET_BEGINNING);
  557.     Read(SwapFile, FrameBase + FrameOffset, PAGE_SIZE);
  558.     Close(SwapFile);
  559.  
  560. #if defined(DEBUG_PAGING)
  561.     printf("page %d (%lx) swapped in\n", PageIndex, PageOffset);
  562. #endif
  563.  
  564.     FrameTable[FrameIndex].Age = 0;
  565.     FrameTable[FrameIndex].PageIndex = PageIndex;
  566.     PageTable[PageIndex] = PD_ADDR(FrameBase + FrameOffset) | PD_DT_PAGE;
  567. }
  568.  
  569. /*
  570. ** CorrectPageFault - lock and load all needed pages, signal task to restart
  571. */
  572.  
  573. BOOL CorrectPageFault(VOID)
  574. {
  575.     PFaultNode FaultNode;
  576.     CPTR Faults[4];        /* Data Fault (LSB and MSB), stage B, stage C */
  577.     UWORD FaultCount = 0;
  578.     UWORD Format;
  579.     UWORD PPF;
  580.     static UWORD OldFormat = 0;
  581.     static UWORD SSW = 0;
  582.     UWORD bDiff = FALSE;
  583.  
  584.     Disable();
  585.     FaultNode = (PFaultNode) RemHead((struct List *) & PageFaultList);
  586.     Enable();
  587.     if (!FaultNode) return (FALSE);
  588.  
  589.     Format = FaultNode->Fault.S.VectorOffset & SF_FORMAT_MASK;
  590.  
  591. #if defined(DEBUG)
  592.     PPF = --PendingPageFaults;
  593.     if (PPF)
  594.         printf("PPF=%d ", PPF);
  595.     if (Format != OldFormat)
  596.         OldFormat = Format, bDiff = TRUE;
  597.     if (FaultNode->Fault.S.SpecialStatusReg != SSW)
  598.         SSW = FaultNode->Fault.S.SpecialStatusReg, bDiff = TRUE;
  599.     if (bDiff)
  600.         printf("Format [%4.4x] SSW = %4.4x\n", OldFormat, SSW);
  601. #endif
  602.  
  603.     /* Data Fault is the same for both long and short frames */
  604.     if (!LockPage(FaultNode->Fault.S.DataCycleFaultAddr))
  605.         Faults[FaultCount++] = FaultNode->Fault.S.DataCycleFaultAddr;
  606.  
  607.     /* check LSB of Data Fault */
  608.     if (!LockPage(FaultNode->Fault.S.DataCycleFaultAddr + 3))
  609.         Faults[FaultCount++] = FaultNode->Fault.S.DataCycleFaultAddr + 3;
  610.  
  611.     if (Format == SSF_FORMAT)
  612.     {
  613.         /* stage B address is PC+4, stage C is PC+2 */
  614.         if (!LockPage(FaultNode->Fault.S.PC + 4))
  615.             Faults[FaultCount++] = FaultNode->Fault.S.PC + 4;
  616.         if (!LockPage(FaultNode->Fault.S.PC + 2))
  617.             Faults[FaultCount++] = FaultNode->Fault.S.PC + 2;
  618.     }
  619.     else /* must be LSF_FORMAT */
  620.     {
  621.         /* stage B address is in stack frame, stage C is at B-2 */
  622.         if (!LockPage(FaultNode->Fault.L.StageBAddress))
  623.             Faults[FaultCount++] = FaultNode->Fault.L.StageBAddress;
  624.         if (!LockPage(FaultNode->Fault.L.StageBAddress - 2))
  625.             Faults[FaultCount++] = FaultNode->Fault.L.StageBAddress - 2;
  626.     }
  627.  
  628.     /* load all faulted pages */
  629.     while (FaultCount--) LoadPage(Faults[FaultCount]);
  630.  
  631.     /* wake up the sleeping task (it does the rest) */
  632.     Signal(FaultNode->FaultedTask, 1 << FaultNode->RestartSigNum);
  633.     return (TRUE);
  634. }
  635.  
  636. /*
  637. ** ShowUsage - explain VMEM
  638. */
  639.  
  640. VOID ShowUsage(VOID)
  641. {
  642.     printf("\2330;33mVMem " VMEM_VERSION " ©1990 by Edward Hutchins\2330m\n");
  643.     printf("Usage: VMem [-f <swapfile>] [-p <phys pages>] [-v <virt pages>]\n");
  644.     printf("Note: the default swap file is " DEF_SWAP_FILE_NAME "\n");
  645. }
  646.  
  647. /*
  648. ** Spy - spy on memory usage
  649. */
  650.  
  651. void Spy(void)
  652. {
  653.     UWORD totalpages = PAGE_TABLE_MIN + NumPages;
  654.     WORD xoff = WIDTH - totalpages / 16;
  655.     while (1)
  656.     {
  657.         UWORD i = totalpages;
  658.         while (i--)
  659.         {
  660.             PD_SHORT pd = PageTable[i];
  661.             BYTE pen;
  662.  
  663.             if (i < PAGE_TABLE_MIN)
  664.             {
  665.                 PageTable[i] &= ~(PD_MOD | PD_USED);
  666.                 pen = PEN_UNUSED;
  667.             }
  668.             else pen = PEN_VIRT;
  669.             if ((pd & PD_DT_MASK) == PD_DT_INVALID) pen = PEN_INVALID;
  670.             else if (pd & PD_MOD) pen = PEN_MOD;
  671.             else if (pd & PD_USED) pen = PEN_USED;
  672.             else if (pd & PD_WP) pen = PEN_WP;
  673.             else if (pd & PD_CI) pen = PEN_CI;
  674.             if (pen != SpyPenCache[i])
  675.             {
  676.                 SetAPen(RP, SpyPenCache[i] = pen);
  677.                 WritePixel(RP, 80 + (i / 16), 8 + (i & 15));
  678.             }
  679.         }
  680.     }
  681. }
  682.  
  683. /*
  684. ** SetupSpy - create the spy task
  685. */
  686.  
  687. void SetupSpy(void)
  688. {
  689.     if (!(window = OpenScrn(WIDTH, HEIGHT, DEPTH, 0, 0))) return;
  690.     /* sig = 1 << (window->UserPort->mp_SigBit); */
  691.     LoadRGB4(ViewPortAddress(window), ctable, MAX_PEN);
  692.     RP = window->RPort;
  693.     SetRast(RP, PEN_FRAME);
  694.     CreateTask ("VMEM Spy", -1L, Spy, 4096);
  695. }
  696.  
  697. /*
  698. ** OpenLibs - open the needed libraries
  699. */
  700.  
  701. void OpenLibs( void )
  702. {
  703.     /* we need to open this for some reason */
  704.     ExecBase = (struct ExecBase *) OpenLibrary("exec.library", 0);
  705.     if (!ExecBase) exit( 20 );
  706.  
  707.     GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
  708.     if (!GfxBase) exit( 20 );
  709.     
  710.     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
  711.     if (!IntuitionBase) exit( 20 );
  712. }
  713.  
  714. /*
  715. ** main - VMEM main entry point
  716. */
  717.  
  718. int main(int argc, char *argv[])
  719. {
  720.     ULONG cacr, cpu, fpu, mmu = 0;
  721.     struct MsgPort *AgePort = NULL;
  722.     struct timerequest *TimerReq = NULL;
  723.     ULONG AgeSig;
  724.     ULONG Signals;
  725.     UBYTE DaemonSigNum;
  726.  
  727.     OpenLibs();    
  728.  
  729. #if defined(DEBUG)
  730.     printf("This is the debugging version of VMEM\n\n");
  731. #endif
  732.  
  733.     /* If they're just asking for help */
  734.     if (argc >= 2 && argv[1][0] == '?')
  735.     {
  736.         ShowUsage();
  737.         exit(0);
  738.     }
  739.  
  740.     /* get the system setup */
  741.     cpu = GetCPUType();
  742.     fpu = GetFPUType();
  743.     mmu = GetMMUType();
  744.  
  745.     /* trap silly users */
  746.     if (cpu < 68020 || !mmu)
  747.     {
  748.         printf("Sorry, your system doesn't have the balls for VMEM!\n");
  749.         exit(0);
  750.     }
  751.  
  752.     /* allocate the paging daemon's signal */
  753.     if ((DaemonSigNum = AllocSignal(-1)) == -1) goto Abort;
  754.  
  755.     /* allocate the ageing timer port */
  756.     AgePort = CreatePort(NULL, 0);
  757.     if (AgePort == NULL) goto Abort;
  758.     TimerReq = (PTIMER_REQ) CreateExtIO(AgePort, sizeof(TIMER_REQ));
  759.     if (TimerReq == NULL) goto Abort;
  760.     if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)TimerReq, 0)) goto Abort;
  761.  
  762.     /* parse arguments someday... */
  763.     strcpy(SwapFileName, DEF_SWAP_FILE_NAME);
  764.  
  765. #if 0
  766.     if (argc > 1)
  767.     {
  768.         for (i = 1; i < argc; ++i)
  769.         {
  770.         }
  771.     }
  772. #endif
  773.  
  774.     /* set up both the instruction and data caches */
  775.     cacr = (CACR_INST | CACR_DATA) << CACR_WALLOC;
  776.     cacr |= (CACR_INST | CACR_DATA) << CACR_BURST;
  777.     cacr |= (CACR_INST | CACR_DATA) << CACR_CLEAR;
  778.     cacr |= (CACR_INST | CACR_DATA) << CACR_ENABLE;
  779.     SetCACR(cacr);
  780.  
  781. #if defined(DEBUG)
  782.     printf("MMU Check\n");
  783. #endif
  784.  
  785.     /* see if someone's using the MMU already */
  786.     if (GetTC() & TC_ENB) printf("MMU already in use, resetting...\n");
  787.  
  788. #if defined(DEBUG)
  789.     printf("CreatePageTable()\n");
  790. #endif
  791.  
  792.     /* create the low-level paging tables and set up the MMU */
  793.     if (!CreatePageTable())
  794.     {
  795.         printf("Error: not enough physical memory\n");
  796.         goto Abort;
  797.     }
  798.  
  799. #if defined(DEBUG)
  800.     printf("CreateSwapFile()\n");
  801. #endif
  802.  
  803.     /* open the swap file and make sure it's big enough */
  804.     if (!CreateSwapFile())
  805.     {
  806.         printf("Error: failed to create swap file\n");
  807.         goto Abort;
  808.     }
  809.  
  810.     /* initialize misc variables */
  811.     NewList((struct List *) & PageFaultList);
  812.     PageDaemonTask = FindTask(NULL);
  813.     PageDaemonSig = 1 << DaemonSigNum;
  814.     AgeSig = 1 << AgePort->mp_SigBit;
  815.  
  816.     /* queue a timer request to get us started */
  817.     TimerReq->tr_node.io_Command = TR_ADDREQUEST;
  818.     TimerReq->tr_time.tv_secs = 0;
  819.     TimerReq->tr_time.tv_micro = AGEING_PERIOD;
  820.     SendIO((struct IORequest *) TimerReq);
  821.  
  822.     /*
  823.     ** The point of no return...
  824.     */
  825.  
  826.     SetupSpy();
  827.  
  828.     SetTaskPri(PageDaemonTask, PAGEDAEMON_PRI);
  829.  
  830. #if defined(DEBUG)
  831.     printf("InsertFaultHandler()\n");
  832. #endif
  833.  
  834.     InsertFaultHandler();
  835.  
  836. #if defined(DEBUG)
  837.     printf("AddVirtMem()\n");
  838. #endif
  839.  
  840.     AddVirtMem();
  841.  
  842.  
  843.     /*
  844.     ** This task never exits (system failure would result)
  845.     */
  846.  
  847. #if defined(DEBUG)
  848.     printf("Waiting on %lx\n", PageDaemonSig | AgeSig);
  849. #endif
  850.  
  851.     for (;;)
  852.     {
  853.         Signals = Wait(PageDaemonSig | AgeSig);
  854.  
  855.         if (Signals & AgeSig)
  856.         {
  857. #if defined(DEBUG_AGEING)
  858.             static int nCnt = 0;
  859.             if (nCnt++ % 50 == 0) ShowFrameTableAges();
  860. #endif
  861.  
  862.             GetMsg(AgePort);
  863.             AgeFrameTable();
  864.             TimerReq->tr_node.io_Command = TR_ADDREQUEST;
  865.             TimerReq->tr_time.tv_secs = 0;
  866.             TimerReq->tr_time.tv_micro = AGEING_PERIOD;
  867.             SendIO((struct IORequest *) TimerReq);
  868.         }
  869.  
  870.         if (Signals & PageDaemonSig) while (CorrectPageFault()) ;
  871.     }
  872.  
  873. Abort:            /* we only come here if there was a problem */
  874.     if (DaemonSigNum != -1) FreeSignal(DaemonSigNum);
  875.     if (AgePort) DeletePort(AgePort);
  876.     if (TimerReq) DeleteExtIO((struct IORequest *) TimerReq);
  877.     exit(30);
  878. }
  879.